package terra.model.object;

import java.awt.geom.Line2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import terra.Config;
import terra.model.World;
import terra.model.object.interfaces.Attackable;
import terra.model.object.interfaces.Attacker;
import terra.model.object.knownlist.ObjectKnownList;
import terra.model.object.map.GroundObject;
import terra.network.packet.Packet;
import terra.network.packet.server.battle.ArrowInfo;
import terra.network.packet.server.battle.ArrowStop;

public class Arrow extends MovableObject {

	private static final long serialVersionUID = 1L;

	double angle;
	double imageAngle = 0;
	boolean colided = false;
	Attacker owner;
	long timeAfterCollide = 2000L;
	long collideTime;
	float alpha = 1f;
	transient Line2D shape;
	long startTime;

	public Arrow(int objectId) {
		super(objectId);
		// setKnownList(new ObjectKnownList(this));
		getKnownList().setAutoUpdate(250);
		startTime = System.currentTimeMillis();
	}

	@Override
	public void update(int delta) {
		needUpdate();
		if (System.currentTimeMillis() > startTime + 5000L)
			World.getInstance().removeObject(this);
		if (colided) {
			alpha = (collideTime + timeAfterCollide - System
					.currentTimeMillis()) / 30f * 0.01f;
			if (collideTime + timeAfterCollide < System.currentTimeMillis())
				World.getInstance().removeObject(this);
			return;
		}
		float oldY = getY();
		float oldX = getX();
		setX(getX()
				+ (float) ((getSpeed() / 1000f) * delta * Math.cos(Math
						.toRadians(angle - 90))));
		setY(getY()
				+ (float) ((getSpeed() / 1000f) * delta * Math.sin(Math
						.toRadians(angle - 90))));
		float newY = getY();
		setYacceleration(getYacceleration() + (Config.gravity / 1000f) * delta);
		newY = newY + getYacceleration();
		setY(newY);
		imageAngle = -Math.toDegrees(Math.atan2(oldX - getX(), oldY - getY()));
		shape = new Line2D.Float(getX() + getWidth() / 2, getY() + getHeight()
				/ 2, oldX + getWidth() / 2, oldY + getHeight() / 2);
		GameObject target = isCollision();
		if (target != null && target instanceof Attackable) {
			if (target == owner)
				return;
			((Attackable) target).onHit(owner, owner.getDamage());
			collideTime = System.currentTimeMillis();
			colided = true;
			broadcastStop();
			return;
		}
		GroundObject targetGround = isCollision(getX(), getY());
		if (targetGround != null) {
			targetGround.hit(owner.getDamage());
			collideTime = System.currentTimeMillis();
			colided = true;
			broadcastStop();
		}
	}

	public GameObject isCollision() {
		for (GameObject obj : getKnownList().getKnownObjects().values()) {
			if (!(obj instanceof Attackable))
				continue;
			if (intersects((int) shape.getBounds().getMinX(), (int) shape
					.getBounds().getMinY(), (int) shape.getBounds().getWidth(),
					(int) shape.getBounds().getHeight(), (int) obj.getX(),
					(int) obj.getY(), obj.getWidth(), obj.getHeight())) {
				return obj;
			}
		}
		return null;
	}

	@Override
	public void objectChanged(GObject object) {

	}

	public void broadcastInfo() {
		broadcastPacket(getInfo());
	}

	public void broadcastStop() {
		ArrowStop info = new ArrowStop();
		info.oId = getObjectId();
		broadcastPacket(info);
	}

	@Override
	public Packet getInfo() {
		ArrowInfo info = new ArrowInfo();
		info.x = getX();
		info.y = getY();
		info.oId = getObjectId();
		info.ownerOId = ((GameObject) owner).getObjectId();
		info.w = getWidth();
		info.h = getHeight();
		info.speed = getSpeed();
		info.gravity = Config.gravity;
		info.angle = angle;
		return info;
	}

	@Override
	public ObjectKnownList getKnownList() {
		if (knownList == null)
			return knownList = new ObjectKnownList(this);
		return knownList;
	}
	
	 private void writeObject(ObjectOutputStream oos) throws IOException {}

	 private void readObject(ObjectInputStream ois) throws IOException,ClassNotFoundException {}
}
